package pers.gxm.security.hello.configuration;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import pers.gxm.security.hello.filter.JwtAuthenticationTokenFilter;

import javax.sql.DataSource;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {

//    @Autowired
    private final PasswordEncoder passwordEncoder;
//    @Autowired
    private final UserDetailsService userDetailsService;

    private final DataSource dataSource;

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    public AuthorizationServer(PasswordEncoder passwordEncoder,
                               UserDetailsService userDetailsService,
                               DataSource dataSource){
        this.passwordEncoder = passwordEncoder;
        this.userDetailsService = userDetailsService;
        this.dataSource = dataSource;
    }

    @Bean
    //声明TokenStore实现
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Bean
//            声明 ClientDetails实现
    public ClientDetailsService clientDetails() {
        JdbcClientDetailsService jdbcClientDetailsService = new
        JdbcClientDetailsService(dataSource);
        jdbcClientDetailsService.setPasswordEncoder(passwordEncoder);
        return jdbcClientDetailsService;
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//        clients.inMemory().withClient("gxm")
//                .secret(passwordEncoder.encode("123123123"))
//                .redirectUris("http://www.baidu.com")
//                .authorizedGrantTypes("authorization_code","refresh_token")
//                .scopes("read:user");//令牌允许获取的资源权限
//        使用jdbc存储
         clients.withClientDetails(clientDetails());
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//        开启刷新令牌必须指定
        endpoints.userDetailsService(userDetailsService);
//                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
//                .pathMapping("/oauth/token","/mg_oauth/token");

//        endpoints.authenticationManager(authenticationManager);
//        认证管理器,在支持密码模式时使用
        endpoints.tokenStore(tokenStore());
        //配置令牌存储为数据库存储启动测试,发现数据库中已经存储相关的令牌
//配置TokenServices参数
        DefaultTokenServices tokenServices = new DefaultTokenServices();
//        修改默认令牌⽣成服务
tokenServices.setTokenStore(endpoints.getTokenStore());
//基于数据库令牌⽣成
        tokenServices.setSupportRefreshToken(true);
//        是否⽀持刷新令牌
        tokenServices.setReuseRefreshToken(true);
//        是否重复使⽤刷新令牌（直到过期）

        tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
//        设置客户端信息

        tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
//        ⽤来控制令牌存储增强策略
//访问令牌的默认有效期（以秒为单位）。过期的令牌为零或负数。
        tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30));
//         30天
//         刷新令牌的有效性（以秒为单位）。如果⼩于或等于零，则令牌将不会过期
        tokenServices.setRefreshTokenValiditySeconds((int)
            TimeUnit.DAYS.toSeconds(3));
//3天
            endpoints.tokenServices(tokenServices);
//使⽤配置令牌服务

    }


    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.addTokenEndpointAuthenticationFilter(jwtAuthenticationTokenFilter);
    }
}